import pandas as pd
import os, re
import numpy as np
import soundfile as sf
from IPython.display import clear_output
import pickle
import librosa
from sklearn.preprocessing import StandardScaler
from tensorflow.keras.utils import to_categorical
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.callbacks import ReduceLROnPlateau, EarlyStopping
from tensorflow.keras.models import load_model
from tensorflow.keras import Model
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
from sklearn.metrics import det_curve, DetCurveDisplay
import plotly.express as px
import plotly
import matplotlib.pyplot as plt
import plotly.graph_objects as go
long_data_frame_LSTM = pd.read_csv("C:/Users/zbugo/Desktop/praktyki_zadania/20/data/long_data_frameLSTM.csv")
long_data_frame_GRU = pd.read_csv("C:/Users/zbugo/Desktop/praktyki_zadania/20/data/long_data_frameGRU.csv")
long_data_frame_RNN = pd.read_csv("C:/Users/zbugo/Desktop/praktyki_zadania/20/data/long_data_frameRNN.csv")
df_curve_list = []
colors = []
model_name = []
all_data = []
list_for_FRR_FAR = []
LSTM.¶
genuine = long_data_frame_LSTM[long_data_frame_LSTM['genuine']]
impostor = long_data_frame_LSTM[~long_data_frame_LSTM['genuine']]
data = genuine, impostor
all_data.append(data)
FAR, FRR, thresholds = det_curve(y_true=long_data_frame_LSTM['genuine'], y_score=long_data_frame_LSTM['score'])
arg_of_best_threshold = np.argmin(np.abs(FAR - FRR))
df_curve = pd.DataFrame({
'False Acceptance Rate': FAR[::10],
'False Rejection Rate': FRR[::10]
}, index=thresholds[::10])
df_curve.index.name = "Thresholds"
df_curve.columns.name = "Rate"
df_curve_list.append(df_curve)
colors.append('blue')
model_name.append('LSTM')
FAR_FRR = FAR, FRR
list_for_FRR_FAR.append(FAR_FRR)
GRU.¶
genuine = long_data_frame_GRU[long_data_frame_GRU['genuine']]
impostor = long_data_frame_GRU[~long_data_frame_GRU['genuine']]
data = genuine, impostor
all_data.append(data)
FAR, FRR, thresholds = det_curve(y_true=long_data_frame_GRU['genuine'], y_score=long_data_frame_GRU['score'])
arg_of_best_threshold = np.argmin(np.abs(FAR - FRR))
y = np.mean(a = np.array(FAR[arg_of_best_threshold], FRR[arg_of_best_threshold]))
x = thresholds[arg_of_best_threshold]
df_curve = pd.DataFrame({
'False Acceptance Rate': FAR[::10],
'False Rejection Rate': FRR[::10]
}, index=thresholds[::10])
df_curve.index.name = "Thresholds"
df_curve.columns.name = "Rate"
df_curve_list.append(df_curve)
colors.append('red')
model_name.append('GRU')
FAR_FRR = FAR, FRR
list_for_FRR_FAR.append(FAR_FRR)
RNN.¶
genuine = long_data_frame_RNN[long_data_frame_RNN['genuine']]
impostor = long_data_frame_RNN[~long_data_frame_RNN['genuine']]
data = genuine, impostor
all_data.append(data)
FAR, FRR, thresholds = det_curve(y_true=long_data_frame_RNN['genuine'], y_score=long_data_frame_RNN['score'])
arg_of_best_threshold = np.argmin(np.abs(FAR - FRR))
y = np.mean(a = np.array(FAR[arg_of_best_threshold], FRR[arg_of_best_threshold]))
x = thresholds[arg_of_best_threshold]
df_curve = pd.DataFrame({
'False Acceptance Rate': FAR[::10],
'False Rejection Rate': FRR[::10]
}, index=thresholds[::10])
df_curve.index.name = "Thresholds"
df_curve.columns.name = "Rate"
df_curve_list.append(df_curve)
colors.append('brown')
model_name.append('Classic RNN')
FAR_FRR = FAR, FRR
list_for_FRR_FAR.append(FAR_FRR)
Wykresy.¶
Wszystkie modele zostały wytrenowane na podstawie macierzy MFCC, połączonej z macierzami pierwszej i drugiej pochodnej obliczonymi na podstawie MFCC, aby zapewnić lepsze i dokładniejsze uczenie modelu.¶
# Tworzenie figure z jednym wykresem w kolumnie i tyloma wierszami, ile wynosi długość all_data.
fig, axes = plt.subplots(len(all_data), 1, figsize=(14, 6 * len(all_data)))
# Iteracja przez dane i rysowanie wykresów.
for i in range(len(all_data)):
ax = axes[i] # Wybór odpowiedniego osi (subplotu).
# Rysowanie histogramów dla genuine i impostor.
ax.hist(all_data[i][0]['score'], bins=128, alpha=0.5, label='genuine')
ax.hist(all_data[i][1]['score'], bins=128, alpha=0.5, label='impostor')
# Ustawienia osi i tytułu.
ax.set_xlim(-1, 1)
ax.legend()
ax.set_title(model_name[i])
ax.grid()
# Wyświetlanie wykresów.
plt.tight_layout()
plt.show()
Pierwsze dwa histogramy, odpowiadające sieciom neuronowym LSTM i GRU, są do siebie bardzo podobne. Różnice między nimi są zauważalne, ale stosunkowo niewielkie. Natomiast ostatni histogram, przedstawiający klasyczny RNN, znacząco się różni. Wartości score dla genuine i impostor nachodzą na siebie, co sugeruje, że embeddingi wygenerowane przez ten model są bardzo słabe. Dobre odseparowanie przy użyciu dowolnego thresholdu wydaje się niemożliwe. Może postprocessing mógłby częściowo poprawić wyniki tego modelu. Kolejne wykresy dostarczą więcej informacji na temat jakości analizowanych modeli.
plotly.offline.init_notebook_mode()
# Lista kolorów dla różnych modeli
# Tworzenie pustego wykresu
fig_thresh = go.Figure()
# Iteracyjne dodawanie krzywych do wykresu
for i, df_curve in enumerate(df_curve_list):
legend_group = model_name[i] # Grupa legendy dla modelu
# Dodanie linii dla FAR (z przypisaną grupą legendy)
fig_thresh.add_trace(go.Scatter(
x=df_curve.index, y=df_curve['False Acceptance Rate'],
mode='lines',
line=dict(color=colors[i]),
name='FAR',
legendgroup=legend_group, # Przypisanie do grupy
showlegend=False # Ukrycie wpisu dla FAR w legendzie
))
# Dodanie linii dla FRR (z przypisaną grupą legendy)
fig_thresh.add_trace(go.Scatter(
x=df_curve.index, y=df_curve['False Rejection Rate'],
mode='lines',
line=dict(color=colors[i]), # Inny styl dla FRR (przerywana linia)
name='FRR',
legendgroup=legend_group, # Przypisanie do grupy
showlegend=False # Ukrycie wpisu dla FRR w legendzie
))
# Znalezienie najlepszego threshold (EER)
arg_of_best_threshold = np.argmin(np.abs(df_curve['False Acceptance Rate'] - df_curve['False Rejection Rate']))
x = df_curve.index[arg_of_best_threshold]
y = np.mean([df_curve['False Acceptance Rate'].iloc[arg_of_best_threshold], df_curve['False Rejection Rate'].iloc[arg_of_best_threshold]])
# Dodanie punktu dla EER (z przypisaną grupą legendy)
fig_thresh.add_trace(go.Scatter(
x=[x], y=[y],
mode='markers',
marker=dict(size=10, color=colors[i]),
name='EER',
legendgroup=legend_group, # Przypisanie do grupy
showlegend=False # Ukrycie wpisu dla EER w legendzie
))
# Dodanie tylko jednego wpisu do legendy dla całego modelu
fig_thresh.add_trace(go.Scatter(
x=[None], y=[None], # Wpis do legendy bez dodawania nowych danych
mode='lines',
line=dict(color=colors[i]),
name=model_name[i], # Nazwa modelu w legendzie
legendgroup=legend_group, # Przypisanie do tej samej grupy
showlegend=True # Pokaż w legendzie
))
# Dostosowanie osi i tytułu
fig_thresh.update_layout(
title="FRR, FAR EER for types of RNN",
xaxis_title="Thresholds",
width=1200,
height=600
)
# Wyświetlenie wykresu
fig_thresh.show()
Na wykresie można odczytać wartości FAR i FRR dla różnych wartości thresholdu, co umożliwia znalezienie kompromisu w postaci EER, czyli punktu przecięcia się krzywych FAR i FRR. Im mniejsza wartość EER, tym wyższa skuteczność modelu.
Oprócz samej wartości EER warto również przeanalizować dynamikę FAR i FRR, co może być przydatne przy podejmowaniu decyzji, czy model ma działać w sposób "zachłanny", akceptując wysokie wartości FAR (model user-friendly), czy w sposób restrykcyjny, akceptując wysokie wartości FRR (model bezpieczny).
Analizując krzywe FAR i FRR dla różnych modeli, najgorzej wypada klasyczne RNN – jego wartość EER jest najwyższa, co wskazuje na niską skuteczność tego modelu. Z kolei LSTM i GRU wykazują bardzo podobne przebiegi krzywych FAR i FRR, a ich wartości EER są zbliżone. Jeśli jednak konieczne byłoby wskazanie najlepszego modelu na podstawie wartości EER, LSTM wypada minimalnie lepiej.
Przy tym wyborze sugerowałem się wyłącznie wartością EER. Warto jednak pamiętać, że model o najniższym EER nie zawsze będzie najlepszym rozwiązaniem, w zależności od tego, czy priorytetem jest zachłanność (niski FRR, wysoki FAR), czy bezpieczeństwo (niski FAR, wysoki FRR). W takich przypadkach szczególnie ważne staje się dokładne przeanalizowanie dynamiki obu wskaźników.
plotly.offline.init_notebook_mode()
fig = go.Figure()
for i in range(0,len(list_for_FRR_FAR)):
FAR, FRR = list_for_FRR_FAR[i]
fig.add_trace(go.Scatter(x=FAR, y=FRR, name=model_name[i], mode='lines'))
fig.update_layout(
title='Krzywa DET',
xaxis_title='FAR',
yaxis_title='FRR',
width=1200,
height=600
)
fig.update_xaxes(range=[0, 0.35])
fig.update_yaxes(range=[0, 0.55])
fig.show()